package com.tianquan.miracle.context;/**
 * @author starsea
 * @date 2024-09-30 上午11:16
 */

import com.tianquan.miracle.annotation.Configuration;
import com.tianquan.miracle.aop.*;
import com.tianquan.miracle.beans.BeanDefinition;
import com.tianquan.miracle.beans.DefaultBeanFactory;
import com.tianquan.miracle.conditional.parseConditionPostProcessor;
import com.tianquan.miracle.core.EnableAutoConfiguration;
import com.tianquan.miracle.listener.core.EventListener;
import com.tianquan.miracle.listener.core.EventSourceManager;
import com.tianquan.miracle.listener.print.PrintEvent;
import com.tianquan.miracle.postprocessor.BeanPostProcessor;
import com.tianquan.miracle.postprocessor.InjectBeanPostProcessor;
import com.tianquan.miracle.util.MiracleUtils;
import com.tianquan.miracle.util.ServiceClassLoader;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * @BelongsProject: uploaddemo
 * @BelongsPackage: com.tianquan.miracle.context
 * @Author: tianquan
 * @CreateTime: 2024-09-30  11:16
 * @Description: 抽象应用上下文
 * @Version: 1.0
 */
public abstract class AbstractApplicationContext implements ApplicationContext {

    protected void preBeanPostProcessor(DefaultBeanFactory defaultBeanFactory) {

        // 初始化框架需要的Bean
        InitializingNecessaryBean(defaultBeanFactory);

        // 将自动配置类加入到容器中
        loadAutoConfiguration(defaultBeanFactory);

        // 拓展类,只需要了给全类名就可以在创建用户Bean前自定义Bean实现
        Set<String> classNameSet = extendPreBeanPostProcessor();
        // 注入到容器中
        for (String className : classNameSet) {
            try {
                Class<?> clazz = Class.forName(className);
                String beanName = MiracleUtils.createBeanName(clazz);
                BeanDefinition beanDefinition = new BeanDefinition(beanName, clazz, "singleton");
                defaultBeanFactory.registerBeanDefinition(beanName, beanDefinition);
                defaultBeanFactory.getBean(beanName);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }

    }

    protected void parseCreateAspectBean(DefaultBeanFactory defaultBeanFactory) {
        List<BeanDefinition> allBeanDefinition = defaultBeanFactory.getAllBeanDefinition();
        for (BeanDefinition beanDefinition : allBeanDefinition) {
            Class<?> aClass = beanDefinition.getaClass();
            Aspect annotation = aClass.getAnnotation(Aspect.class);
            if (annotation == null) continue;
            Method[] methods = aClass.getDeclaredMethods();
            // 创建切面类
            AopEntity aopEntity = new AopEntity();
            // 设置切面类
            aopEntity.setObject(MiracleUtils.getBean(aClass));
            Pointcut pointcut = null;
            Method poinctcutMethod = null;
            for (Method method : methods) {
                // 设置切点
                Pointcut var1 = method.getAnnotation(Pointcut.class);
                if (var1 != null && pointcut == null) {
                    pointcut = var1;
                    poinctcutMethod = method;
                }
                // 设置前置通知
                if (MiracleUtils.parseMethod(method, Before.class) != null
                        && aopEntity.getBeforeMethod() == null) aopEntity.setBeforeMethod(method);
                // 设置环绕通知
                if (MiracleUtils.parseMethod(method, Around.class) != null
                        && aopEntity.getAroundMethod() == null) aopEntity.setAroundMethod(method);
                // 设置后置通知
                if (MiracleUtils.parseMethod(method, After.class) != null
                        && aopEntity.getAfterMethod() == null) aopEntity.setAfterMethod(method);
            }
            // 当前方法没有切点直接解析一下bean定义对象
            if (pointcut == null) continue;

            // 判断切点方法是否为空
            if (aopEntity.getBeforeMethod() == null
                    && aopEntity.getAfterMethod() == null
                    && aopEntity.getAroundMethod() == null)
                continue;

            // 判断切点方法和通知上面的方法是否一致
            MiracleUtils.cheekAnnotation(aopEntity, poinctcutMethod.getName());

            // 设置需要代理的方法
            String[] methodList = pointcut.method();
            if (methodList != null && methodList.length > 0)
                Arrays.stream(methodList).forEach(s -> defaultBeanFactory.putAopMethodsName(s, aopEntity));

            // 设置需要代理的类
            Class<?>[] classes = pointcut.classArray();
            if (classes != null && classes.length > 0)
                Arrays.stream(classes).forEach(aClass1 -> defaultBeanFactory.putAopClass(aClass1, aopEntity));

            // 设置需要代理的注解
            Class<? extends Annotation>[] annotations = pointcut.annotation();
            if (annotations != null && annotations.length > 0)
                Arrays.stream(annotations).forEach(a -> defaultBeanFactory.putAopAnnotationName(a, aopEntity));
        }
    }

    private void InitializingNecessaryBean(DefaultBeanFactory defaultBeanFactory) {
        // 加载依赖注入需要的处理器
        List<InjectBeanPostProcessor> InjectBeanPostProcessor = ServiceClassLoader.Loader(InjectBeanPostProcessor.class);
        defaultBeanFactory.addInjectBeanPostProcessors(InjectBeanPostProcessor);
        // 加载条件解析需要的处理器
        List<parseConditionPostProcessor> parseConditionPostProcessors = ServiceClassLoader.Loader(parseConditionPostProcessor.class);
        defaultBeanFactory.addParseConditionPostProcessors(parseConditionPostProcessors);
    }

    protected void postProcessorBeanDefinitionRegistry(DefaultBeanFactory defaultBeanFactory) {
        List<BeanDefinition> allBeanDefinition = defaultBeanFactory.getAllBeanDefinition();
        for (BeanDefinition beanDefinition : allBeanDefinition) {
            Class<?> aClass = beanDefinition.getaClass();
            // 判断改class有没有实现BeanPostProcessor接口
            if (BeanPostProcessor.class.isAssignableFrom(aClass)) {
                // 先实例化该类
                BeanPostProcessor beanPostProcessor = (BeanPostProcessor) defaultBeanFactory.getBean(MiracleUtils.createBeanName(aClass));
                defaultBeanFactory.addBeanPostProcessor(beanPostProcessor);
            }
        }
    }

    private void loadAutoConfiguration(DefaultBeanFactory defaultBeanFactory) {
        // 是否开启自动配置类
        if (!isEnabled()) return;

        // 拿到所有能自动配置的类
        Set<String> classNameSet = ServiceClassLoader.getClassName(EnableAutoConfiguration.class);
        excludeNOAutoConfiguration(classNameSet);
        if (classNameSet == null) return;
        for (String className : classNameSet) {
            try {
                Class<?> aClass = Class.forName(className);
                Configuration configuration = aClass.getAnnotation(Configuration.class);
                if (configuration != null) {
                    String beanName = MiracleUtils.createBeanName(aClass);
                    BeanDefinition beanDefinition = new BeanDefinition(beanName, aClass, "singleton");
                    defaultBeanFactory.registerBeanDefinition(beanName, beanDefinition);
                }
            } catch (ClassNotFoundException ignored) {
                System.out.println();
            } finally {
                // 添加到容器中
                defaultBeanFactory.loadBean();
            }
        }
    }

    private void excludeNOAutoConfiguration(Set<String> classNameSet) {
        // todo 排除掉用户不需要自动配置的类
    }

    public void initBeanDefinition(DefaultBeanFactory defaultBeanFactory) {
        // 扫描要添加的bean
        List<Class<?>> classesInPackageAndSubpackages = findClassesInPackageAndSubpackages();
        for (Class<?> clazz : classesInPackageAndSubpackages) {
            String BeanName = MiracleUtils.sanComponent(clazz);
            if (BeanName == null) continue;
            BeanDefinition beanDefinition = new BeanDefinition(BeanName, clazz, "singleton");
            defaultBeanFactory.registerBeanDefinition(BeanName, beanDefinition);
        }
    }

    void InitializingBeans(DefaultBeanFactory defaultBeanFactory) {
        defaultBeanFactory.loadBean();
    }

    public void postBeanPostProcessor(DefaultBeanFactory defaultBeanFactory, EventSourceManager eventSourceManager) {
        // 将实现了EventListener接口的类注册到监听器管理者里面
        List<EventListener> listeners = defaultBeanFactory.selectBean(EventListener.class);
        eventSourceManager.addEventListeners(listeners);
        // 发布打印事件
        eventSourceManager.publishEvent(new PrintEvent(null));
    }

    abstract Boolean isEnabled();

    public abstract List<Class<?>> findClassesInPackageAndSubpackages();

    public abstract Set<String> extendPreBeanPostProcessor();

}
